package be.ipl.finito.servlets;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.ejb.EJB;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import be.ipl.finito.domaine.Joueur;
import be.ipl.finito.domaine.Partie;
import be.ipl.finito.domaine.Plateau;
import be.ipl.finito.usecases.GestionPartie;
import be.ipl.finito.utilitaires.GestionAttente;
import be.ipl.finito.utilitaires.ListeParties;

/**
 * Servlet implementation class Menu
 */
@WebServlet(name = "servletAttente.html")
public class Attente extends HttpServlet
{
	private static final long serialVersionUID = 1L;
	private static Logger LOGGER = Logger.getLogger("Attente JSP");

	public static String PAGE_ATTTENTE = "attente.html";
	public static String PAGE_JEU = "servletJeu.html";
	public static String PAGE_ERREUR = "erreur.html";
	public static String PAGE_MENU = "menu.html";

	@EJB
	GestionPartie gestionPartie;
	@EJB
	GestionPartie gestionJoueur;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
	{
		// declaration

		final ServletContext context = getServletContext();
		final HttpSession httpSession = request.getSession();

		final GestionAttente gestionnaireAttente;
		final Map<Partie, GestionAttente> mapGestionnaireAttente;
		final Partie partie;
		String destination; // redirection

		final ListeParties partiesActives;
		ListeParties partiesEnAttente;

		final int idPartie = Integer.parseInt((String) httpSession.getAttribute("partie_id"));
		final Joueur joueur = (Joueur) httpSession.getAttribute("joueur");
		final int idJoueur = joueur.getId();

		synchronized (context) {
			context.setAttribute("gestionPartie", gestionPartie); // TODO essaier d'eviter si j'ai le temps parce que c'est vraiment moche
		}

		// recupere le gestionnaire de partie dans le context
		if (context.getAttribute("gestionnairePartie") == null) {
			mapGestionnaireAttente = new HashMap<Partie, GestionAttente>();
			synchronized (context) {
				context.setAttribute("gestionnairePartie", mapGestionnaireAttente);
			}
		} else {
			mapGestionnaireAttente = (Map<Partie, GestionAttente>) context.getAttribute("gestionnairePartie");
		}

		// recupere la liste des parties actives dans le context
		if (context.getAttribute("partiesActives") == null) {
			partiesActives = new ListeParties();
			synchronized (context) {
				context.setAttribute("partiesActives", partiesActives);
			}
		} else {
			partiesActives = (ListeParties) context.getAttribute("partiesActives");
		}

		// recupere la liste des parties en attente
		partiesEnAttente = (ListeParties) context.getAttribute("partiesEnAttente");

		// fin declaration

		// Si la partie � commenc� on se fait forward
		if (partiesActives.contientPartieId(idPartie)) {

			if (!partiesActives.contientJoueursId(idPartie, joueur)) {
				httpSession.setAttribute("erreurs", "La partie à déjà commencer et vous n'etes pas actif dedans votre id");

				response.sendRedirect(PAGE_ERREUR);
				return;
			}

			LOGGER.info("forward jeu car la partie est active");
			response.sendRedirect(PAGE_JEU);
			return;
		}

		// on est sur que la partie n'est pas lance
		// recupere l'objet partie auquel le joueur veut acceder
		partie = partiesEnAttente.getPartieId(idPartie);

		// Verifie si le joueur est dans est bien dans une partie en attente
		final List<String> erreurs = verificationParamettre(idJoueur, partie, partiesEnAttente);
		if (erreurs.size() != 0) {
			request.setAttribute("erreurs", erreurs);
			this.getServletContext().getNamedDispatcher(PAGE_ERREUR).forward(request, response);
			return;
		}

		// recupere le gestionnaire d'attente de la partie
		// si il n'existe pas init
		if (mapGestionnaireAttente.get(partie) == null) {
			gestionnaireAttente = new GestionAttente(partie, joueur, this);
			mapGestionnaireAttente.put(partie, gestionnaireAttente);
		} else {
			gestionnaireAttente = mapGestionnaireAttente.get(partie);
			mapGestionnaireAttente.put(partie, gestionnaireAttente);
		}

		// Si le joueur souhaite quitter l'attente
		if (request.getParameter("quitter") != null) {
			gestionnaireAttente.enleverJoueur(joueur);

			partiesEnAttente.get(partie).remove(joueur);
			if (partiesEnAttente.get(partie).size() == 0) {
				partiesEnAttente.remove(partie);
			}

			synchronized (context) {
				context.setAttribute("partiesEnAttente", partiesEnAttente);
			}

			LOGGER.info("forward menu car quitter");
			response.sendRedirect(PAGE_MENU);
			return;
		}

		// si il ne veut pas quitter, on l'ajoute
		gestionnaireAttente.ajouterJoueur(joueur);

		// affiche la liste des joueurs present et le temps restant
		partiesEnAttente = (ListeParties) context.getAttribute("partiesEnAttente");

		final List<Joueur> joueursPresent = partiesEnAttente.get(partie);
		final List<Joueur> joueursAttendu = partie.getJoueurs();

		httpSession.setAttribute("nom", partie.getNom());
		httpSession.setAttribute("joueursPresents", joueursPresent);
		httpSession.setAttribute("joueursAttendus", joueursAttendu);
		httpSession.setAttribute("tempsRefresh", Partie.TEMPS_REFRESH + "; url=/bombermanitoJsp/servletAttente.html");

		Plateau plateau = null;
		final HashSet<Plateau> plateaux = new HashSet<>(partie.getPlateaux());
		final Iterator<Plateau> it = plateaux.iterator();
		while (it.hasNext()) {
			final Plateau p = it.next();

			if (p.getId() == partie.getId()) {
				plateau = p;
				break;
			}
		}

		if (plateau == null) {
			throw new InternalError("plateau non disponnible");
		}

		// Recupere la destination
		destination = gestionnaireAttente.getDestination();
		LOGGER.info("forward final vers " + destination + " partie :" + idPartie + " - " + partie.getId() + " joueur :" + idJoueur);
		response.sendRedirect(destination);
		return;
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	@Override
	protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
	{
		doGet(request, response);
	}

	public static List<String> verificationParamettre(final int idJoueur, final Partie partie, final Map<Partie, List<Joueur>> partiesActives)
	{

		final List<String> erreurs = new ArrayList<String>();

		if (partie == null) {
			erreurs.add("Cette partie n'est pas active ou n'existe pas");
			erreurs.add("Joueur " + idJoueur);
			return erreurs;
		}

		if (partie.estEnCours() && !partie.contientJoueur(idJoueur)) {
			erreurs.add("Vous n'êtes pas inscrit dans cette partie");
			return erreurs;
		}

		final List<Joueur> joueurs = partiesActives.get(partie);
		for (final Joueur joueur : joueurs) {
			if (joueur.getId() == idJoueur) {
				return erreurs;
			}
		}

		erreurs.add("Vous n'êtes pas actif dans cette partie");
		return erreurs;
	}
}
